
package test;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;

public class RSASecurityUtil {
    /** 指定加密算法为RSA */
    private static final String ALGORITHM = "RSA";
    /** 密钥长度，用来初始化 */
    private static final int KEYSIZE = 1024;

    /**
     * 加密方法
     * @return
     * @throws Exception
     */
	public static String paramsConstruct(Map<String,String> paramsMap, String publicKeyStr) throws Exception {
		String params = "";
		Map<String, String> sParaNew = ParamsUtil.paraFilter(paramsMap,true);
		for (String key : sParaNew.keySet()) {
			sParaNew.put(key, URLEncoder.encode(sParaNew.get(key),"UTF-8"));
		}
		// 获取待签名字符串
		String preSignStr = ParamsUtil.createLinkString(sParaNew);
		String sign = encrypt(preSignStr,publicKeyStr);
		for (String key : sParaNew.keySet()) {
			sParaNew.put(key, URLEncoder.encode(sParaNew.get(key),"UTF-8"));
		}
		String linkString = ParamsUtil.createLinkString(sParaNew);
		params = linkString + "&sign=" + URLEncoder.encode(sign, "UTF-8");
		return params;
	}

    public static String encrypt(Map<String,String> paramsMap, String publicKeyStr) throws Exception {
	    Map<String, String> sParaNew = ParamsUtil.paraFilter(paramsMap,true);
	    // 获取待签名字符串
	    String preSignStr = ParamsUtil.createLinkString(sParaNew);
	    return encrypt(preSignStr,publicKeyStr);
    }
    
    public static String encrypt(String source, String publicKeyStr) throws Exception {
    	
    	Key publicKey = geneneratePublicKey((new BASE64Decoder()).decodeBuffer(publicKeyStr));

        return encrypt(source,publicKey);
    }
    
    public static String encrypt(String source, Key publicKey) throws Exception {
    	  /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] b = source.getBytes();
        /** 执行加密操作 */
		int inputLen = b.length;
		int offLen = 0;//偏移量
		int i = 0;
		ByteArrayOutputStream bops = new ByteArrayOutputStream();
		while(inputLen - offLen > 0){
			byte [] cache;
			if(inputLen - offLen > 117){
				cache = cipher.doFinal(b, offLen,117);
			}else{
				cache = cipher.doFinal(b, offLen,inputLen - offLen);
			}
			bops.write(cache);
			i++;
			offLen = 117 * i;
		}
		bops.close();
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bops.toByteArray());
    }

    /**
     * 解密算法
     * @param cryptograph    密文
     * @return
     * @throws Exception
     */
    
    public static String decrypt(String cryptograph, String privateKeyStr) throws Exception {
        
    	Key privateKey = generatePrivateKey((new BASE64Decoder()).decodeBuffer(privateKeyStr));
    	
    	return decrypt(cryptograph,privateKey);
    }
    
    public static String decrypt(String cryptograph, Key privateKey) throws Exception {
    	 /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] b1 = decoder.decodeBuffer(cryptograph);
        
        /** 执行解密操作 */
        byte[] b = cipher.doFinal(b1);
        return new String(b);
    }
    
	public static PrivateKey generatePrivateKey(byte[] decodeKeyinfo) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {	
		KeySpec keySpec = new PKCS8EncodedKeySpec(decodeKeyinfo);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		return keyFactory.generatePrivate(keySpec);
	}
	
	public static PublicKey geneneratePublicKey(byte[] decodeKeyinfo) throws NoSuchAlgorithmException, InvalidKeySpecException{
		KeySpec keySpec = new X509EncodedKeySpec(decodeKeyinfo);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		return keyFactory.generatePublic(keySpec);
	}
	
	public static boolean verifySign(String orginStr, String sign, String decryptKey) throws Exception{
		if(isBlank(sign)){
			return false;
		}
		
		String targetStr = decrypt(sign, decryptKey);
		if(orginStr.equals(targetStr)){
			return true;
		}
		return false;
	}
	
	public static boolean verifySign(Map<String, String> paramsMap, String sign, String decryptKey) throws Exception{
	    Map<String, String> sParaNew = ParamsUtil.paraFilter(paramsMap, true);
	    // 获取待签名字符串
	    String preSignStr = ParamsUtil.createLinkString(sParaNew);
	    
		return verifySign(preSignStr,sign,decryptKey);
	}

	/**
	 * 字符串是否为空白
	 * @param cs 被检测的字符串
	 * @return 若为空白，则返回 true
	 */
	public static boolean isBlank(final CharSequence cs) {
		int strLen;
		if (cs == null || (strLen = cs.length()) == 0) {
			return true;
		}
		for (int i = 0; i < strLen; i++) {
			if (!Character.isWhitespace(cs.charAt(i))) {
				return false;
			}
		}
		return true;
	}
}
